import re

from PyQt5.QtCore import Qt, pyqtSlot, pyqtSignal
from PyQt5.QtWidgets import QDialog

import ui_findandreplacedlg

MAC = "qt_mac_set_native_menubar" in dir()


class FindAndReplaceDlg(QDialog, ui_findandreplacedlg.Ui_FindAndReplaceDlg):
    found = pyqtSignal(int)
    notFound = pyqtSignal()

    def __init__(self, text, parent=None):
        super(FindAndReplaceDlg, self).__init__(parent)

        self._text = text
        self._index = 0
        self.setupUi(self)
        # 这个过程有个潜在重要价值，QtCore.QMetaObject.connectSlotsByName()执行后，可以不用显式connect，
        # 直接使用on_widgetName_signalName的方法，默认就建立了连接关系。
        # 比如 on_findLineEdit_textEdited()这种方法，在文档改变后，直接触发。
        if not MAC:
            self.findButton.setFocusPolicy(Qt.NoFocus)  # Tab键会跳过这些个按钮
            self.replaceButton.setFocusPolicy(Qt.NoFocus)
            self.replaceAllButton.setFocusPolicy(Qt.NoFocus)
        self.updateUi()

    @pyqtSlot("QString")
    def on_findLineEdit_textEdited(self, text):
        self._index = 0
        self.updateUi()

    def updateUi(self):
        enable = bool(self.findLineEdit.text())
        self.findButton.setEnabled(enable)
        self.replaceAllButton.setEnabled(enable)
        self.replaceButton.setEnabled(enable)

    def text(self):
        return self._text

    @pyqtSlot()
    def on_findButton_clicked(self):
        regex = self.makeRegex()
        match = regex.search(self._text, self._index)
        if match is not None:
            self._index = match.end()#在匹配项的最后更新索引位置，以备下次查找
            self.found.emit(match.start()) #发射信号，带有匹配位置
        else:
            self._index=match.start()
            self.notFound.emit()

    def makeRegex(self):
        findText=self.findLineEdit.text()
        if self.syntaxComboBox.currentText()=="Literal":
            findText=re.escape(findText) #> 可以对字符串中所有可能被解释为正则运算符的字符进行转义的应用函数
            # re.escape('www.python.org')解释 'www\\.python\\.org'
        flags=re.MULTILINE|re.DOTALL|re.UNICODE #修改正则运行方式，如换行，大小写敏感等。
        if not self.caseCheckBox.isChecked():
            flags|=re.IGNORECASE
        if self.wholeCheckBox.isChecked():
            findText=r"\b%s\b" % findText
        return re.compile(findText,flags)
    @pyqtSlot()
    def on_replaceButton_clicked(self):
        regex=self.makeRegex()
        self._text=regex.sub(self.replaceLineEdit.text(),self._text,1)

    @pyqtSlot()
    def on_replaceAllButton_clicked(self):
        regex=self.makeRegex()
        self._text=regex.sub(self.replaceLineEdit.text(),self._text)

if __name__ == '__main__':
    import sys
    from PyQt5.QtWidgets import QApplication

    text = """US experience shows that, unlike traditional patents,
    software patents do not encourage innovation and R&D, quite the
    contrary. In particular they hurt small and medium-sized enterprises
    and generally newcomers in the market. They will just weaken the market
    and increase spending on patents and litigation, at the expense of
    technological innovation and research. Especially dangerous are
    attempts to abuse the patent system by preventing interoperability as a
    means of avoiding competition with technological ability.
    --- Extract quoted from Linus Torvalds and Alan Cox's letter
    to the President of the European Parliament
    http://www.effi.org/patentit/patents_torvalds_cox.html"""

    def found(where):
        print("Found at %d" % where)

    def nomore():
        print("No more found")

    app=QApplication(sys.argv)
    form=FindAndReplaceDlg(text)
    form.found.connect(found)
    form.notFound.connect(nomore)
    form.show()
    app.exec()
    print(form.text())



